﻿using System;
using System.Collections.Generic;

namespace 协变和逆变
{
    class Program
    {
        public class Person { }
        public class Student : Person { }
        static void Main(string[] args)
        {
            ///背景
            /// 协变和逆变 是 C# 4.0 里面出现的新的语法
            /// C# 2.0 添加了泛型 这个东西（解决了代码重用这个问题）
            /// C# 4.0 添加了泛型接口 的协变和逆变。（协变和逆变可以说是泛型的一个补丁）

            Person p1 = new Person();
            Person p2 = new Student();
            //Student s1 = new Person(); //编译错误

            ///第一个和第二个没啥好说的
            ///第三个也很合理，C#语法就是这个样子的

            List<Person> listp1 = new List<Person>();
            //List<Person> listp2 = new List<Student>();  //编译错误

            ///第一个没啥好说的
            ///第二个其实也能理解   
            ///     Person p2 = new Student(); 没问题是因为 Person 是 Student 的父类(或者叫基类),C# 语法就是允许这么干
            ///     List<Person> listp2 = new List<Student>(); 好好想想也对，Person 是 Student 的父类没错
            ///         但是 List<Person> 不是 List<Student>() 的父类。
            ///         所以也没啥问题。

            IEnumerable<Person> elistp1 = new List<Person>();
            IEnumerable<Person> elistp2 = new List<Student>();
            var tempList = elistp2 as List<Student>;
            ///第一个没啥好说的
            ///第二个就是协变   和泛型一样能让我们少写一些代码

            IMyList<Student, Person> myList1 = new MyList<Student, Person>();
            IMyList<Student, Person> myList2 = new MyList<Student, Student>();//协变
            IMyList<Student, Person> myList3 = new MyList<Person, Person>();//逆变
            IMyList<Student, Person> myList4 = new MyList<Person, Student>();//协变+逆变

            ///
            ///
            /// 
            /// 协变和逆变的语法
            /// 只能放在接口或者委托的泛型接口前面
            /// out 协变covariant 修饰返回值
            /// in  逆变contravariant 修饰传入参数
            ///

            Func<Student, Person> f = null;////协变+逆变
            Action<Student, Student> a = null;//逆变
            IEnumerable<Student> tempList111 = null;//协变

        }
    }
    public interface IMyList<in t1, out t2> { }
    public class MyList<t1, t2> : IMyList<t1, t2> { }

}
